/**
 * TDS PEC 4
 * Grupo 3H2M
 *
 * El paquete <code>edu.uoc.tds.pec4.server.bbdd</code> agrupa todas las clases
 * que encapsulan los objetos de acceso a datos (DAO),para realizar el acceso
 * a datos. La base de datos es PostgreSQL.
 */
package edu.uoc.tds.pec4.server.bbdd;

import edu.uoc.tds.pec4.beans.AulaDTO;
import edu.uoc.tds.pec4.beans.LocalizacionDTO;
import edu.uoc.tds.pec4.beans.ReservaDTO;
import edu.uoc.tds.pec4.common.filters.FiltroFechasHoras;
import edu.uoc.tds.pec4.common.util.Constantes;
import edu.uoc.tds.pec4.common.util.UtilSQL;
import edu.uoc.tds.pec4.server.bbdd.exceptions.DataBaseDAOException;
import java.sql.PreparedStatement;
import java.util.List;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

/**
 * La clase <code>ReservaDAO</code> es el componente de software que suministra
 * la implementación relacionada con la entidad Reserva y todas sus adyacentes.
 * Principalmente, da servicio a los subsistemas de Aulas para gestionar las 
 * reservas.<br />
 * Extiende la clase <code>DataBaseDAO</code><br />
 *
 * @author	Silvia López Ruiz
 * @author	Luis Rodríguez-Manzaneque Sánchez
 * @version	08/12/2011
 * @since	1.00
 * @see         edu.uoc.tds.pec4.server.bbdd.exceptions.DataBaseDAOException
 */
public class ReservaDAO extends DataBaseDAO implements IReservaDAO{

    private PreparedStatement pstmtInsRes;
    private PreparedStatement pstmtUpdSol;
      
    public ReservaDAO() throws DataBaseDAOException {
        super();

    }

    /**
     * Método que permite dar de alta la reserva de un espacio.
     * @param   reserva La reserva a dar de alta en la BBDD
     * @throws  DataBaseDAOException En caso de generarse una excepción de acceso
     *          a la base de datos se dispara al nivel superior
     */
    public void insertarReserva(ReservaDTO reserva) throws DataBaseDAOException {
        if (reserva == null) {
            throw new DataBaseDAOException(DataBaseDAOException.RESERVA_NULA);
        }
        
        try {
            pstmtInsRes = super.preparedStatement("INSERT INTO reserva (idreserva,estado,idempleado,idaula,importe) "
                        + "VALUES (?, ?, ?, ?, ?)");
            pstmtUpdSol = super.preparedStatement("UPDATE solicitud set estado=? where idsolicitud=?");
            
            // Envolvemos la secuencia de inserts dentro de una transacción
            super.setAutoCommit(false);
            pstmtInsRes.clearParameters();
            pstmtInsRes.setInt(1, reserva.getIdReserva());
            pstmtInsRes.setInt(2, Constantes.RESERVA_ASIGNADA);
            pstmtInsRes.setString(3, reserva.getIdEmpleado());
            pstmtInsRes.setInt(4, reserva.getIdAula());
            pstmtInsRes.setDouble(5, reserva.getImporte());
            pstmtInsRes.execute();
    
            // Cambiamos el estado de la solicitud a atendida
            pstmtUpdSol.setInt(1, Constantes.SOLICITUD_ATENDIDA);
            pstmtUpdSol.setInt(2, reserva.getIdReserva());
            pstmtUpdSol.execute();
            
            super.commit();

            pstmtInsRes.close();
            pstmtUpdSol.close();

        } catch (SQLException eS) {
            super.rollback();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_ALTA_RESERVA
                    + Constantes.SL + eS.getMessage());
        } finally {
            super.setAutoCommit(true);
        }
    }  
    
    public void actualizarImporteReserva(ReservaDTO reserva) throws DataBaseDAOException {
        if (reserva == null) {
            throw new DataBaseDAOException(DataBaseDAOException.RESERVA_NULA);
        }
        
        try {
            pstmtUpdSol = super.preparedStatement("UPDATE reserva set importe=? where idreserva=?");
            
            // Envolvemos la secuencia de inserts dentro de una transacción
            super.setAutoCommit(false);
            
            // Cambiamos el importe de la reserva atendida
            pstmtUpdSol.setDouble(1, reserva.getImporte());
            pstmtUpdSol.setInt(2, reserva.getIdReserva());
            pstmtUpdSol.execute();
            
            super.commit();

            pstmtUpdSol.close();

        } catch (SQLException eS) {
            super.rollback();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_ALTA_RESERVA
                    + Constantes.SL + eS.getMessage());
        } finally {
            super.setAutoCommit(true);
        }
    }
    
    /**
     * Devuelve la lista de Solicitudes que existen actualmente.
     * @return  La lista de todos los Solicitudes de la aplicación
     * @throws  DataBaseDAOException En caso de generarse una excepción de acceso
     *          a la base de datos se dispara al nivel superior
     */
    @Override
    public List<AulaDTO> listaAulasLibres(int idCiudad, FiltroFechasHoras fechasHoras) 
            throws DataBaseDAOException {

        List<AulaDTO> aulas = new ArrayList<AulaDTO>();
        try {
            // Montamos la consulta
            String sSQL = "SELECT idaula, nombre as nombreAula, direccion, superficie,"
                    + " aforo, preciohora, preciodia, porcentcancelacion"
                    + " FROM aula WHERE idaula not in ("   
                        // Subselect que devuelve las aulas ocupadas para ese rango
                        + " SELECT a.idaula"
                        + " FROM aula a inner join reserva r"
                        + " on a.idaula=r.idaula"
                        + " inner join solicitud s "
                        + " on r.idreserva=s.idsolicitud "
                        + " WHERE a.inactivo=" + Constantes.ACTIVO
                        + " AND s.idciudad=" + idCiudad
                        + " AND NOT ("
                            + " s.fechaini>'" + UtilSQL.formatDateSQL(fechasHoras.getFechaFin()) 
                            + "' or s.fechafin<'" + UtilSQL.formatDateSQL(fechasHoras.getFechaInicio()) + "' "
                        + ") "
                    + ") ";
                    
            sSQL += " AND idciudad=" + idCiudad;
            sSQL += " ORDER BY preciohora";

            // Lanzamos la consulta contra la BBDD
            ResultSet objRS = super.obtenerConsulta(sSQL);


            // Recorremos el ResultSet para cargar el vector
            while (objRS.next()) {
                AulaDTO aula = new AulaDTO();
                aula.setIdAula(objRS.getInt("idAula"));
                aula.setNomAula(objRS.getString("nombreAula"));
                aula.setDireccion(objRS.getString("direccion"));
                aula.setSuperficie(objRS.getDouble("superficie"));
                aula.setAforo(objRS.getInt("aforo"));
                aula.setPrecioHora(objRS.getDouble("preciohora"));
                aula.setPrecioDia(objRS.getDouble("preciodia"));
                aula.setPorcentCancelacion(objRS.getDouble("porcentcancelacion"));
                aulas.add(aula);
            }

            // Liberamos recursos
            objRS.close();
            objRS = null;

        } catch (SQLException eS) {
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_LEER_AULAS_LIBRES_BBDD
                    + Constantes.SL + eS.getMessage());
        } catch (Exception eE) {
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_AULAS_GENERAL
                    + Constantes.SL + eE.getMessage());
        }
        return aulas;
    }
    

    public ReservaDTO getReserva(int idReserva) throws DataBaseDAOException {
        
        ReservaDTO res = new ReservaDTO();
        try {
            // Montamos la consulta
            String sSQL = "SELECT r.idreserva, s.fechaSol as fechaSol, us.nombre as nomCliente,"
                    + " s.idsolicitud as numSolicitud, s.fechaSol as fechaSol, s.horaSol as horaSol, "
                    + " r.idAula, a.nombre as nomAula, a.superficie as superficie, a.aforo as aforo,"
                    + " s.fechaini as fechaDesde, s.fechafin as fechaFin, s.horaini as horaIni,"
                    + " s.horafin as horaFin, s.diacompleto as diaCompleto, "
                    + " c.nombre as nomciudad, pr.nombre as nomprov, pa.nombre as nompais, "
                    + " r.importe"
                    + " FROM reserva r inner join solicitud s"
                    + " on r.idreserva=s.idsolicitud"
                    + " inner join aula a "
                    + " on a.idaula=r.idaula "
                    + " inner join ciudad c"
                    + " on s.idciudad=c.idciudad "
                    + " inner join provincia pr "
                    + " on c.idprovincia=pr.idprovincia "
                    + " inner join pais pa "
                    + " on pr.idpais=pa.idpais"
                    + " inner join usuario us "
                    + " on s.idcliente=us.idusuario"
                    + " WHERE r.idreserva='"+idReserva+"'";

            // Lanzamos la consulta contra la BBDD
            ResultSet objRS = super.obtenerConsulta(sSQL);


            // Recorremos el ResultSet para cargar el objeto DTO
            if (objRS.next()) {
                res.setIdReserva(objRS.getInt("idReserva"));
                res.setFechaSol(objRS.getDate("fechaSol"));
                res.setNomCliente(objRS.getString("nomCliente"));
                res.setNumSolicitud(objRS.getInt("numSolicitud"));
                res.setFechaSol(objRS.getDate("fechaSol"));
                res.setHoraSol(objRS.getTime("horaSol"));
                res.setIdAula(objRS.getInt("IdAula"));
                res.setNomAula(objRS.getString("nomAula"));
                res.setSuperficie(objRS.getDouble("superficie"));
                res.setAforo(objRS.getInt("aforo"));
                res.setFechaDesde(objRS.getDate("fechaDesde"));
                res.setFechaHasta(objRS.getDate("fechaFin"));
                res.setHoraIni(objRS.getTime("horaIni"));
                res.setHoraFin(objRS.getTime("horaFin"));
                res.setDiaCompleto(objRS.getBoolean("diaCompleto"));
                res.setNomCiudad(objRS.getString("nomCiudad"));
                res.setNomProvincia(objRS.getString("nomProv"));
                res.setNomPais(objRS.getString("nomPais"));
                res.setImporte(objRS.getDouble("importe"));
                
            } else {
                // No existe una reserva con el id pasado
                throw new DataBaseDAOException(DataBaseDAOException.NO_EXISTE_RESERVA);
            }

            // Liberamos recursos
            objRS.close();
            objRS = null;

        } catch (SQLException eS) {
            eS.printStackTrace();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_LEER_RESERVAS_BBDD
                + Constantes.SL + eS.getMessage());
        } catch (Exception eE) {
            eE.printStackTrace();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_AULAS_GENERAL
                + Constantes.SL + eE.getMessage());
        }
        return res;
    }

    public ReservaDTO getDetalleReserva(int idReserva) throws DataBaseDAOException {
        
        ReservaDTO res = new ReservaDTO();
        try {
            // Montamos la consulta
            String sSQL = "SELECT idreserva, s.estado, u.idusuario as nomEmpleado, a.idaula, importe"
                    + " FROM reserva r inner join solicitud s"
                    + " on r.idreserva=s.idsolicitud"
                    + " inner join usuario u"
                    + " on r.idempleado=u.idusuario"
                    + " inner join aula a "
                    + " on a.idaula=r.idaula "
                    + " WHERE r.idreserva='"+idReserva+"'";

            System.out.println(sSQL);

            // Lanzamos la consulta contra la BBDD
            ResultSet objRS = super.obtenerConsulta(sSQL);


            // Recorremos el ResultSet para cargar el objeto DTO
            if (objRS.next()) {
                res.setIdReserva(objRS.getInt("idReserva"));
                res.setEstado(objRS.getInt("estado"));
                res.setNomEmpleado(objRS.getString("nomEmpleado"));
                res.setIdAula(objRS.getInt("idAula"));
                res.setImporte(objRS.getDouble("importe"));
                
            } else {
                // No existe una reserva con el id pasado
                throw new DataBaseDAOException(DataBaseDAOException.NO_EXISTE_RESERVA);
            }

            // Liberamos recursos
            objRS.close();
            objRS = null;

        } catch (SQLException eS) {
            eS.printStackTrace();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_LEER_RESERVAS_BBDD
                + Constantes.SL + eS.getMessage());
        } catch (Exception eE) {
            eE.printStackTrace();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_AULAS_GENERAL
                + Constantes.SL + eE.getMessage());
        }
        return res;
    }
    
    public List<ReservaDTO> listaReservas(LocalizacionDTO local,
      List<Integer> estados,String FechaDesde, String FechaHasta) throws DataBaseDAOException {

      List<ReservaDTO> reservas = new ArrayList<ReservaDTO>();
        try {
            // Montamos la consulta
            String sSQL = "SELECT r.estado, r.idReserva,s.fechaIni as fechaDesde ,s.fechaFin as fechaHasta,"
                    + "s.idCliente as nomcliente,r.idAula,s.idSolicitud as numSolicitud,"
                    + "r.importe"
                    + " FROM reserva r inner join solicitud s"
                    + " on r.idReserva=s.idSolicitud "
                    + " inner join ciudad c"
                    + " on s.idciudad=c.idciudad "
                    + " inner join provincia pr "
                    + " on c.idprovincia=pr.idprovincia "
                    + " inner join pais pa "
                    + " on pr.idpais=pa.idpais"
                    + " inner join usuario us "
                    + " on s.idcliente=us.idusuario"
                    + " WHERE r.idReserva>0";
                    
            
            if (local != null) {
                if ((local.getPais() != null) && (local.getPais().getIdPais() != Constantes.NO_SELECT)) {
                    sSQL += " AND pa.idpais=" + local.getPais().getIdPais();
                }
                if ((local.getProvincia() != null) && (local.getProvincia().getIdProvincia() != Constantes.NO_SELECT)) {
                    sSQL += " AND pr.idprovincia=" + local.getProvincia().getIdProvincia();
                }
                if ((local.getCiudad() != null) && (local.getCiudad().getIdCiudad() != Constantes.NO_SELECT)) {
                    sSQL += " AND s.idciudad=" + local.getCiudad().getIdCiudad();
                }
            }
            if ((estados != null) && (!estados.isEmpty())) {
                sSQL += " AND s.estado in (";
                for (int i : estados) {
                    sSQL += i + ",";
                }
                sSQL = sSQL.substring(0, sSQL.length() - 1);
                sSQL += ")";
            }
            if ((FechaDesde != null) && (!FechaDesde.isEmpty())&& (FechaHasta != null) && (!FechaHasta.isEmpty()) ) {
                sSQL += " AND (s.fechaIni BETWEEN to_date('" + FechaDesde + "','dd-mm-yyyy') AND to_date('"+FechaHasta+"','dd-mm-yyyy'))";
            }
                         
            sSQL += " ORDER BY s.fechasol";

            // Lanzamos la consulta contra la BBDD
            ResultSet objRS = super.obtenerConsulta(sSQL);


            // Recorremos el ResultSet para cargar el vector
            while (objRS.next()) {
                ReservaDTO res = new ReservaDTO();
                res.setEstado(objRS.getInt("estado"));
                res.setIdReserva(objRS.getInt("idReserva"));
                res.setFechaDesde(objRS.getDate("fechaDesde"));
                res.setFechaHasta(objRS.getDate("fechaHasta"));
                res.setNomCliente(objRS.getString("nomCliente"));
                res.setIdAula(objRS.getInt("IdAula"));
                res.setNumSolicitud(objRS.getInt("numSolicitud"));
                reservas.add(res);
            }

            // Liberamos recursos
            objRS.close();
            objRS = null;

        } catch (SQLException eS) {
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_LEER_RESERVAS_BBDD
                    + Constantes.SL + eS.getMessage());
        } catch (Exception eE) {
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_AULAS_GENERAL
                    + Constantes.SL + eE.getMessage());
        }
        return reservas;
    }

}

